<?php

class WSB_Form_Editor
{

	/** @var WSB_Db_Row */
	private $_item;

	/** @var Zend_Config */
	private $_config;

	/** @var string The table class name */
	private $_tableClass;

	/** @var string The database table name */
	private $_tableName;

	/** @var Zend_Form */
	private $_form;

	/** @var array */
	private $_buttons;

	/** @var Zend_Form */
	private $_subform;

	/** @var array */
	private $_subformHiddens;

	/**
	 * The constructor
	 *
	 * @param WSB_Db_Row $item
	 */
	public function __construct(WSB_Db_Row $item)
	{
		$this->_item = $item;
		$this->_tableClass = $item->getTableClass();
		$this->_tableName = $item->getTableName();
		$this->_buttons = array();
		$this->_form = new Zend_Form();
		$this->_form->addElementPrefixPath('WSB_Filter', 'WSB/Filter', 'filter');
		$this->_form->addElementPrefixPath('WSB_Validator', 'WSB/Validator', 'validate');
		$this->_form->removeDecorator('HtmlTag');
		$this->_form->addDecorator(array('FooBar' => 'HtmlTag'), array('tag' => 'div'));
		// Subform fuer alle Elemente einer Tabelle
		$this->_subform = new Zend_Form_SubForm();
		$this->_subform->addPrefixPath('WSB_Form_Element', 'WSB/Form/Element', 'element');
		$this->_subform->removeDecorator('DtDdWrapper');
		$this->_subformHiddens = array();
	}

	/**
	 * Set configurations to overwrite base form rendering
	 *
	 * @param Zend_Config $config
	 */
	public function overwriteWithConfig(Zend_Config $config)
	{
		$this->_config = $config;
	}

	/**
	 * @param string $action
	 */
	public function setFormAction($action)
	{
		$this->_form->setAction($action);
	}

	/**
	 * @param string $method
	 */
	public function setFormMethod($method)
	{
		$this->_form->setMethod($method);
	}

	/**
	 * Retrieve form based on Zend_Form
	 *
	 * @return Zend_Form
	 */
	public function getForm()
	{

		foreach($this->getTableMetadata() AS $info) {

			$columnName = $info['COLUMN_NAME'];
			$label = $this->_item->translate($columnName);
			$primary = intval($info['PRIMARY']);
			$value = $this->_item->$columnName;

			// Primary
			if($primary === 1) {
				$element = new Zend_Form_Element_Hidden($columnName);
				$element->addFilter('Int');
				$element->setValue($value);
				$element->setDecorators(array('ViewHelper'));
				array_push($this->_subformHiddens, $columnName);

				// InstanceId
			} else if($columnName == 'instance_id') {
				$element = new Zend_Form_Element_Hidden($columnName);
				$element->addFilter('Int');
				$element->setValue($value);
				$element->setDecorators(array('ViewHelper'));
				array_push($this->_subformHiddens, $columnName);

				// Deleted
			} else if($columnName == 'deleted') {
				$element = new Zend_Form_Element_Hidden($columnName);
				$element->addFilter('Int');
				$element->setValue($value);
				$element->setDecorators(array('ViewHelper'));
				array_push($this->_subformHiddens, $columnName);

				// Hidden
			} else if($columnName == 'hidden') {
				/*
				$options = array('0' => 'No', '1' => 'Yes');
				$element = new Zend_Form_Element_Radio($columnName);
				$element->setLabel($label)
				->setMultiOptions($options);
				$element->addFilter('Int');
				$element->setValue($value);
				*/
				$element = new Zend_Form_Element_Checkbox($columnName);
				$element->setLabel($label);
				$element->addFilter('Int');
				if((intval($value) == 1) || !empty($_POST[$this->_tableClass][$columnName])) {
					$element->setChecked(true);
				}



				// Einfache Labels
			} else if(in_array($columnName, array('created', 'modified'))) {

				/*
				$dateTime = empty($value) ? '-' : date('Y.m.d H:i:s', $value);

				$element = new Zend_Form_Element_Text($columnName);
				$element->helper = 'formNote';
				$element->setLabel($label);
				$element->setValue($dateTime);
				*/
				continue;

				// Feld: sorting
			} else if($columnName == 'sorting') {

				$table = new $this->_tableClass();
				$adapter = $table->getAdapter();
				$where = $adapter->quoteInto('deleted=?', 0);
				$where .= ' AND ' . $adapter->quoteInto('instance_id=?', $this->_item->instance_id);
				$pairs = $table->fetchPairs('sorting', 'sorting', $where, 'sorting');
				if(empty($pairs)) {
					$pairs[] = 0;
				} else {
					$pairs[] = count($pairs);
				}
				$element = new Zend_Form_Element_Select($columnName, array('multiOptions' => $pairs));
				$element->setLabel($label);
				$element->addFilter('Int');
				$element->setValue($value);


				// 1:N (Foreignkey)
			} else if($this->_item->hasParentTable($columnName)) {

				$parentTable = $this->_item->getParentTableByColumns($columnName);
				if($parentTable instanceof WSB_Db_Table) {
					$collection = $parentTable->fetchAll('deleted=0');
					$options = array();
					$options[''] = '';
					foreach($collection AS $item) {
						$options[$item->getPrimaryValue()] = $item->getTitle();
					}
					$element = new Zend_Form_Element_Select($columnName, array('multiOptions' => $options));
					$element->setLabel($label);
					$element->addFilter('Int');
					$element->setValue($value);
				}

			}

			else {

				$element = new Zend_Form_Element_Text($columnName);
				$element->setLabel($label);
				$element->setValue($value);

			}

			$this->_subform->addElement($element);

		}

		// Uebersteuern
		if($this->_config instanceof Zend_Config) {
			$array = $this->_config->toArray();
			foreach($array AS $key=>$spec) {
				// Label
				if(empty($array[$key]['options']['label'])) {
					$label = $this->_item->translate($key);
					$array[$key]['options']['label'] = $label;
				}
				// Value
				if(empty($array[$key]['options']['value'])) {
					$value = $this->_item->$key;
					$array[$key]['options']['value'] = $value;
				}
				// Via INI.config koennen keine leeren Keys definiert werden
				// Als Workaround wird fuer einen leeren Key "empty" definiert.
				// Dieser Key wird hier mit "" ueberschrieben.
				if(isset($spec['options']['multiOptions'])) {
					if(array_key_exists('empty', $spec['options']['multiOptions'])) {
						$emptyValue = $spec['options']['multiOptions']['empty'];
						unset($spec['options']['multiOptions']['empty']);
						$array[$key]['options']['multiOptions'] = array("" => $emptyValue) + $spec['options']['multiOptions'];
					}
				}
			}
			$this->_subform->addElements($array);
		}

		// Subgroup for hidden fields
		$this->_subform->addDisplayGroup($this->_subformHiddens, 'hiddenfields');
		$displayGroup = $this->_subform->getDisplayGroup('hiddenfields');
		$displayGroup->removeDecorator('DtDdWrapper');
		$displayGroup->removeDecorator('Fieldset');
		$displayGroup->removeDecorator('HtmlTag');
		//$displayGroup->removeDecorator('FormElements');

		$this->_form->addSubForm($this->_subform, $this->_tableClass);

		if($this->_item->getPrimaryValue() > 0) {

			// M:N Beziehung
			$depTables = $this->_item->getTable()->getDependentTables();
			foreach($depTables AS $depTable) {
				$depTableObj = new $depTable();
				if($depTableObj->isIntersectionTable()) {
					$references = $depTableObj->getReferences();
					$reference = reset($references);
					if($reference['refTableClass'] != $this->_tableClass) {
						$refTableClass = $reference['refTableClass'];
						$depId = $reference['columns'][0];
						$reference = next($references);
						$refId = $reference['columns'][0];
					} else {
						$reference = next($references);
						$refTableClass = $reference['refTableClass'];
						$depId = $reference['columns'][0];
						$reference = prev($references);
						$refId = $reference['columns'][0];
					}
					$refTableObj = new $refTableClass();

					// Verfuegbar (Assoz. Array mit key=ID und value=Label)
					$availableOptions = array();
					foreach($refTableObj->fetchAll('deleted=0') AS $item) {
						$availableOptions[$item->getPrimaryValue()] = $item->getTitle();
					}

					// Zugeordnet (Index Array mit IDs)
					$assignedOptions = array();
					$where = array($refId.'=?' => $this->_item->getPrimaryValue());

					foreach($depTableObj->fetchAll($where) AS $item) {
						if(array_key_exists($item->$depId, $availableOptions)) {
							$assignedOptions[] = $item->$depId;
						}

					}

					$attribs = array(
					'size' => 5,
					'style' => 'width:200px;');

					$label = $this->_item->translate($depTable);

					$attribs['options'] = $availableOptions;
					$element = new WSB_Form_Element_AdvMultiSelect($depId);
					$element->setLabel($label);
					$element->setValue($assignedOptions);
					$element->setAttribs($attribs);

					$this->_subform = new Zend_Form_SubForm();
					$this->_subform->removeDecorator('DtDdWrapper');
					$this->_subform->addElement($element);

					$element = new Zend_Form_Element_Hidden($refId);
					$element->setValue($this->_item->getPrimaryValue());
					$element->removeDecorator('Label');
					$element->removeDecorator('HtmlTag');
					$this->_subform->addElement($element);
					/*
					$label = $this->_item->translate($depTable);
					$element = $this->_view->formMultiSelect($depTable . '[' . $depId . ']', $assignedOptions, $attribs, $availableOptions);
					$this->_form->addElement($label, $element);
					$this->_form->addHidden($this->_view->formHidden($depTable . '[' . $refId . ']', $this->_item->$primary));
					*/

					$this->_form->addSubForm($this->_subform, $depTable);

				}

			}
		}

		if(!empty($this->_buttons)) {
			$this->_form->addDisplayGroup($this->_buttons, 'buttons');
			$displayGroup = $this->_form->getDisplayGroup('buttons');
			$displayGroup->removeDecorator('DtDdWrapper');
			$displayGroup->addAttribs(array('class' => 'fieldset-buttons'));
			/*$displayGroup = $this->_form->getDisplayGroup('buttons');
			$displayGroup->removeDecorator('DtDdWrapper');
			$displayGroup->removeDecorator('Fieldset');
			$displayGroup->removeDecorator('HtmlTag');*/
		}

		/*
		foreach($this->_form->getElements() AS $element) {
			if($element instanceof Zend_Form_Element_Hidden) {
				//$element->removeDecorators('DtDdWrapper');
				$element->clearDecorators();
			}

		}
		*/
		// Setze Default CSS-Klasse
		foreach($this->_form->getSubforms() AS $this->_subform) {
			foreach($this->_subform AS $element) {
				if($element instanceof Zend_Form_Element) {

					$label = $element->getDecorator('label');
					if($label instanceof Zend_Form_Decorator_Label) {
						$label->setRequiredSuffix('*');
					}

					$class = '';
					switch($element->getType()) {
						case 'Zend_Form_Element_Text':
							$class = 'form-default-element-text';
							break;
						case 'Zend_Form_Element_Textarea':
							$class = 'form-default-element-textarea';
							break;
						case 'Zend_Form_Element_Password':
							$class = 'form-default-element-password';
							break;
						case 'Zend_Form_Element_Checkbox':
							$class = 'form-default-element-checkbox';
							break;
						case 'WSB_Form_Element_RTE':
							$class = 'form-default-element-rte';
							break;
						case 'Zend_Form_Element_Select':
							$class = 'form-default-element-select';
							break;
						case 'WSB_Form_Element_SelectCsvAdvImages':
							$class = 'form-default-element-select';
							break;
					}
					$element->setAttrib('class', $class);
				} else {
					//out($element);
				}
			}
		}
		Zend_Registry::set('Zend_Form_Values', $this->_form->getValues());
		return $this->_form;
	}

	/**
	 * Add submit form element to displaygroup "buttons"
	 *
	 * @param string $name
	 * @param array|Zend_Config $options
	 */
	public function addSubmit($name, $options = null)
	{
		$this->_form->addElement('submit', $name, $options);
		array_push($this->_buttons, $name);
	}

	/**
	 * Add button form element to displaygroup "buttons"
	 *
	 * @param string $name
	 * @param array|Zend_Config $options
	 */
	public function addButton($name, $options = null)
	{
		$this->_form->addElement('button', $name, $options);
		array_push($this->_buttons, $name);
	}

	/**
	 * Set redirect url (used after saving record)
	 *
	 * @param string $redirect
	 */
	public function setRedirect($redirect)
	{
		$element = new Zend_Form_Element_Hidden('redirect');
		$element->setValue($redirect);
		//$element->setDecorators(array('ViewHelper'));
		$element->removeDecorator('Label');
		$element->removeDecorator('HtmlTag');
		$this->_form->addElement($element);
	}

	/**
	 * Get metadata of current table.
	 *
	 * @return array
	 */
	private function getTableMetadata()
	{
		$info = $this->_item->info();
		return $info['metadata'];
	}

}
